﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NCP.Recruiting.ApplicationServices.Interfaces;
using NCP.Recruiting.ApplicationServices.Messaging.Settings;
using NCP.Recruiting.Domain.Aggregates.Tags;
using NCP.Recruiting.ApplicationServices.Contracts;
using NCP.Recruiting.ApplicationServices.Exceptions;
using NCP.Recruiting.ApplicationServices.ModelConversions;
using NCP.Recruiting.ApplicationServices.ViewModels;
using NCP.Recruiting.Domain.Aggregates.Departments;
using NCP.Recruiting.Domain.Aggregates.MessageTemplates;
using NCP.Infrastructure.Common;

namespace NCP.Recruiting.ApplicationServices.Implementations
{
    public class SettingAppService : ISettingAppService
    {
        private readonly ITagRepository _tagRepository;
        private readonly IDepartmentRepository _departmentRepository;
        private readonly IMessageTemplateRepository _messageTemplateRepository;

        public SettingAppService(ITagRepository tagRepository,
            IDepartmentRepository departmentRepository,
           IMessageTemplateRepository _messageTemplateRepository)
        {
            this._tagRepository = tagRepository;
            this._departmentRepository = departmentRepository;
            this._messageTemplateRepository = _messageTemplateRepository;
        }

        #region Tag
        public CreateTagResponse CreateTag(CreateTagRequest request)
        {
            Tag assignedTag = AssignPropertiesToDomain(request.TagProperties);
            assignedTag.GenerateNewIdentity();
            assignedTag.DateCreated = DateTime.Now;
            assignedTag.LastUpdated = DateTime.Now;
            ThrowExceptionIfCustomerIsInvalid(assignedTag);

            try
            {
                _tagRepository.Add(assignedTag);
                _tagRepository.UnitOfWork.Commit();

                return new CreateTagResponse();
            }
            catch (Exception ex)
            {
                return new CreateTagResponse() { Exception = ex };
            }
        }

        public UpdateTagResponse UpdateTag(UpdateTagRequest request)
        {
            try
            {
                Tag existingTag = _tagRepository.Get(request.Id);

                if (existingTag != null)
                {
                    Tag assignedTag = AssignPropertiesToDomain(request.TagProperties);

                    // 这里之所以又被转换一次，是因为，这里是领域对象之间的值交换，上面是ViewModel到领域对象的转换。
                    existingTag.TagName = assignedTag.TagName;
                    existingTag.Selected = assignedTag.Selected;
                    existingTag.LastUpdated = DateTime.Now;

                    ThrowExceptionIfCustomerIsInvalid(existingTag);

                    _tagRepository.Modify(existingTag);
                    _tagRepository.UnitOfWork.Commit();

                    return new UpdateTagResponse();
                }
                else
                {
                    return new UpdateTagResponse() { Exception = GetStandardCustomerNotFoundException() };
                }
            }
            catch (Exception ex)
            {
                return new UpdateTagResponse() { Exception = ex };
            }

        }

        public DeleteTagResponse DeleteTag(DeleteTagRequest request)
        {
            try
            {
                Tag tag = _tagRepository.Get(request.Id);
                if (tag != null)
                {
                    tag.Deleted = true;
                    tag.LastUpdated = DateTime.Now;

                    _tagRepository.Modify(tag);
                    _tagRepository.UnitOfWork.Commit();
                    return new DeleteTagResponse();
                }
                else
                {
                    return new DeleteTagResponse() { Exception = GetStandardCustomerNotFoundException() };
                }

            }
            catch (Exception ex)
            {
                return new DeleteTagResponse() { Exception = ex };
            }
        }

        public GetTagResponse GetTag(GetTagRequest request)
        {
            var response = new GetTagResponse();
            Tag tag = null;

            try
            {
                tag = _tagRepository.Get(request.Id);
                if (tag != null)
                {
                    response.TagProperties = tag.ConvertToViewModel();
                }
                else
                {
                    response.Exception = GetStandardCustomerNotFoundException();
                }
            }
            catch (Exception ex)
            {
                response.Exception = ex;
            }

            return response;
        }

        public FindTagsResponse FindTags(FindTagsRequest request)
        {
            if (request.PageIndex < 0 || request.PageCount <= 0)
                throw new ArgumentException("Invalid");

            FindTagsResponse response = new FindTagsResponse();
            IEnumerable<TagViewModel> matchedTags = null;

            try
            {
                matchedTags = _tagRepository.GetPaged(request.PageIndex, request.PageCount, TagSpecifications.GetTagsByCompanyId(request.CompanyId), t => t.TagCount, true).ConvertToViewModels();
                response.Tags = matchedTags;
            }
            catch (Exception ex)
            {
                response.Exception = ex;
            }

            return response;
        }

        // 此处相当于领域中的Factory
        private Tag AssignPropertiesToDomain(ICreateTagCommand properties)
        {
            return new Tag
            {
                TagName = properties.TagName,
                Selected = properties.Selected,
                TagCount = properties.TagCount,
                CompanyId = properties.CompanyId,
                Deleted = properties.Deleted
            };
        }

        private void ThrowExceptionIfCustomerIsInvalid(Tag newTag)
        {
            // 处理业务检验
        }

        private void ThrowExceptionIfCustomerIsInvalid(Department newDepartment)
        {
        }

        private void ThrowExceptionIfCustomerIsInvalid(MessageTemplate newMessageTemplate)
        {
        }

        private ResourceNotFoundException GetStandardCustomerNotFoundException()
        {
            return new ResourceNotFoundException("The requested customer was not found.");
        }

        #endregion

        #region Department
        public GetAllDepartmentsResponse GetAllDepartments(GetAllDepartmentsRequest request)
        {
            var depts = this._departmentRepository.GetPagedList(request.PageIndex, request.PageCount, DepartmentSpecifications.GetByCompanyId(request.Id), d => d.DateCreated, false);

            var vmdepts = depts.Select(x => new DepartmentViewModel
            {
                Contact = x.Contact,
                DepartmentName = x.DepartmentName,
                Email = x.Email,
                Fax = x.Fax,
                Id = x.Id,
                Mobile = x.Mobile,
                Tel = x.Tel
            });

            var response = new GetAllDepartmentsResponse
            {
                PagedDepartments = new PagedList<DepartmentViewModel>(vmdepts, depts.PageIndex, depts.PageSize, depts.TotalCount)
            };

            return response;
        }

        public CreateDepartmentResponse CreateDepartment(CreateDepartmentRequest request)
        {
            var department = AssignPropertiesToDepartment(request.DepartmentProperties);

            department.GenerateNewIdentity();
            department.CompanyId = request.CompanyId;
            department.DateCreated = DateTime.Now;
            department.LastUpdated = DateTime.Now;
            department.Deleted = false;

            ThrowExceptionIfCustomerIsInvalid(department);

            try
            {
                _departmentRepository.Add(department);
                _departmentRepository.UnitOfWork.Commit();

                return new CreateDepartmentResponse();

            }
            catch (Exception ex)
            {
                return new CreateDepartmentResponse() { Exception = ex };
            }
        }

        public UpdateDepartmentResponse UpdateDepartment(UpdateDepartmentRequest request)
        {
            try
            {
                Department existingDepartment = _departmentRepository.Get(request.Id);

                if (existingDepartment != null)
                {
                    Department assignedDepartment = AssignPropertiesToDepartment(request.DepartmentProperties);

                    existingDepartment.DepartmentName = assignedDepartment.DepartmentName;
                    existingDepartment.Email = assignedDepartment.Email;
                    existingDepartment.Contact = assignedDepartment.Contact;
                    existingDepartment.Deleted = assignedDepartment.Deleted;
                    existingDepartment.Fax = assignedDepartment.Fax;
                    existingDepartment.Tel = assignedDepartment.Tel;
                    existingDepartment.Mobile = assignedDepartment.Mobile;
                    existingDepartment.LastUpdated = DateTime.Now;

                    ThrowExceptionIfCustomerIsInvalid(existingDepartment);

                    _departmentRepository.Modify(existingDepartment);
                    _departmentRepository.UnitOfWork.Commit();

                    return new UpdateDepartmentResponse();
                }
                else
                {
                    return new UpdateDepartmentResponse() { Exception = GetStandardCustomerNotFoundException() };
                }
            }
            catch (Exception ex)
            {
                return new UpdateDepartmentResponse { Exception = ex };
            }
        }

        public GetDepartmentResponse GetDepartment(GetDepartmentRequest request)
        {
            var response = new GetDepartmentResponse();
            Department department = null;

            try
            {
                department = _departmentRepository.Get(request.Id);

                if (department != null)
                {
                    response.DepartmentProperties = new DepartmentViewModel
                    {
                        Contact = department.Contact,
                        DepartmentName = department.DepartmentName,
                        Email = department.Email,
                        Tel = department.Tel,
                        Fax = department.Fax,
                        Id = department.Id,
                        Mobile = department.Mobile
                    };
                }
                else
                {
                    response.Exception = GetStandardCustomerNotFoundException();
                }
            }
            catch (Exception ex)
            {
                response.Exception = ex;
            }

            return response;
        }

        public DeleteDepartmentResponse DeleteDepartment(DeleteDepartmentRequest request)
        {
            try
            {
                Department department = _departmentRepository.Get(request.Id);
                if (department != null)
                {
                    department.Deleted = true;
                    department.LastUpdated = DateTime.Now;
                    _departmentRepository.Modify(department);
                    _departmentRepository.UnitOfWork.Commit();
                    return new DeleteDepartmentResponse();
                }
                else
                {
                    return new DeleteDepartmentResponse { Exception = GetStandardCustomerNotFoundException() };
                }
            }
            catch (Exception ex)
            {
                return new DeleteDepartmentResponse { Exception = ex };
            }
        }

        private Department AssignPropertiesToDepartment(ICreateDepartmentCommand properties)
        {
            return new Department
            {
                Contact = properties.Contact,
                DepartmentName = properties.DepartmentName,
                Mobile = properties.Mobile,
                Email = properties.Email,
                Tel = properties.Tel,
                Fax = properties.Fax
            };
        }
        #endregion


        #region MessageTemplate
        public CreateMessageTemplateResponse CreateMessageTemplate(CreateMessageTemplateRequest request)
        {
            MessageTemplate assigned = AssignPropertiesToMessageTemplate(request.Properties);
            assigned.GenerateNewIdentity();
            assigned.CompanyId = request.CompanyId;
            assigned.DateCreated = DateTime.Now;
            assigned.LastUpdated = DateTime.Now;
            // Validate
            ThrowExceptionIfCustomerIsInvalid(assigned);

            try
            {
                _messageTemplateRepository.Add(assigned);
                _messageTemplateRepository.UnitOfWork.Commit();

                return new CreateMessageTemplateResponse();
            }
            catch (Exception ex)
            {
                return new CreateMessageTemplateResponse { Exception = ex };
            }
        }

        public UpdateMessageTemplateResponse UpdateMessageTemplate(UpdateMessageTemplateRequest request)
        {
            try
            {
                MessageTemplate existingMessageTemplate = _messageTemplateRepository.Get(request.Id);

                if (existingMessageTemplate != null)
                {
                    MessageTemplate assigned = AssignPropertiesToMessageTemplate(request.Properties);
                    existingMessageTemplate.Subject = assigned.Subject;
                    existingMessageTemplate.Purpose = assigned.Purpose;
                    existingMessageTemplate.TemplateContent = assigned.TemplateContent;
                    existingMessageTemplate.Deleted = assigned.Deleted;
                    existingMessageTemplate.LastUpdated = DateTime.Now;

                    ThrowExceptionIfCustomerIsInvalid(existingMessageTemplate);

                    _messageTemplateRepository.Modify(existingMessageTemplate);
                    _messageTemplateRepository.UnitOfWork.Commit();

                    return new UpdateMessageTemplateResponse();
                }
                else
                {
                    return new UpdateMessageTemplateResponse { Exception = GetStandardCustomerNotFoundException() };
                }
            }
            catch (Exception ex)
            {
                return new UpdateMessageTemplateResponse { Exception = ex };
            }
        }

        public DeleteMessageTemplateResponse DeleteMessageTemplate(DeleteMessageTemplateRequest request)
        {
            try
            {
                MessageTemplate messageTemplate = _messageTemplateRepository.Get(request.Id);
                if (messageTemplate != null)
                {
                    // 设置删除标记
                    messageTemplate.Deleted = true;
                    messageTemplate.LastUpdated = DateTime.Now;

                    _messageTemplateRepository.Modify(messageTemplate);
                    _messageTemplateRepository.UnitOfWork.Commit();
                    return new DeleteMessageTemplateResponse();
                }
                else
                {
                    return new DeleteMessageTemplateResponse() { Exception = GetStandardCustomerNotFoundException() };
                }

            }
            catch (Exception ex)
            {
                return new DeleteMessageTemplateResponse() { Exception = ex };
            }
        }

        public GetMessageTemplateResponse GetMessageTemplate(GetMessageTemplateRequest request)
        {
            var response = new GetMessageTemplateResponse();
            MessageTemplate messageTemplate = null;

            try
            {
                messageTemplate = _messageTemplateRepository.Get(request.Id);

                if (messageTemplate != null)
                {
                    response.Properties = new MessageTemplateViewModel
                    {
                        Id = messageTemplate.Id,
                        Deleted = messageTemplate.Deleted,
                        Purpose = messageTemplate.Purpose,
                        Subject = messageTemplate.Subject,
                        TemplateContent = messageTemplate.TemplateContent
                    };
                }
                else
                {
                    response.Exception = GetStandardCustomerNotFoundException();
                }
            }
            catch (Exception ex)
            {
                response.Exception = ex;
            }

            return response;
        }

        public FindMessageTemplatesResponse FindMessageTemplates(FindMessageTemplatesRequest request)
        {
            var messageTemplates = this._messageTemplateRepository.GetPagedList(request.PageIndex, request.PageCount, MessageTemplateSpecifications.GetAllByCompanyId(request.CompanyId), d => d.DateCreated, false);

            var vmMessageTemplates = messageTemplates.Select(x => new MessageTemplateViewModel
            {
                Id = x.Id,
                Deleted = x.Deleted,
                Purpose = x.Purpose,
                Subject = x.Subject,
                TemplateContent = x.TemplateContent
            });

            var response = new FindMessageTemplatesResponse
            {
                PagedMessageTemplates = new PagedList<MessageTemplateViewModel>(vmMessageTemplates, messageTemplates.PageIndex, messageTemplates.PageSize, messageTemplates.TotalCount)
            };

            return response;
        }

        public GetMessageTemplatesResponse GetMessageTemplates(GetMessageTemplateRequest request)
        {
            var list = this._messageTemplateRepository.GetAll().Where(s => s.Deleted == false
                && s.CompanyId == request.Id).Select(x =>
                new MessageTemplateViewModel
                {
                    Id = x.Id,
                    Subject = x.Subject,
                    Purpose = x.Purpose
                });
            return new GetMessageTemplatesResponse
            {
                MessageTemplates = list.ToList()
            };
        }

        private MessageTemplate AssignPropertiesToMessageTemplate(ICreateMessageTemplateCommand properties)
        {
            return new MessageTemplate
            {
                Purpose = properties.Purpose,
                TemplateContent = properties.TemplateContent,
                Subject = properties.TemplateContent,
                Deleted = properties.Deleted
            };
        }
        #endregion
    }
}
